package com.bolt.support.spring.jpa.handler;

import com.sun.source.tree.Tree;
import com.sun.source.util.TreePath;
import com.sun.tools.javac.api.JavacTrees;
import com.sun.tools.javac.code.Flags;
import com.sun.tools.javac.processing.JavacProcessingEnvironment;
import com.sun.tools.javac.tree.JCTree;
import com.sun.tools.javac.tree.TreeMaker;
import com.sun.tools.javac.util.Context;
import com.sun.tools.javac.util.List;
import com.sun.tools.javac.util.ListBuffer;
import com.sun.tools.javac.util.Names;

import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.Messager;
import javax.annotation.processing.ProcessingEnvironment;
import javax.lang.model.element.Element;
import javax.tools.Diagnostic;
import java.util.ArrayList;

public abstract class BaseProcessor extends AbstractProcessor {

    protected JavacTrees javacTrees; // 提供了待处理的抽象语法树
    protected TreeMaker treeMaker; // 封装了创建AST节点的一些方法
    protected Names names; // 提供了创建标识符的方法

    protected Messager messager;


    @Override
    public synchronized void init(ProcessingEnvironment processingEnv) {
        super.init(processingEnv);
        Context context = ((JavacProcessingEnvironment) processingEnv).getContext();
        javacTrees = JavacTrees.instance(processingEnv);
        treeMaker = TreeMaker.instance(context);
        names = Names.instance(context);
        messager = processingEnv.getMessager();

    }

    protected void addImportInfo(Element element, String packageName, String className) {
        TreePath treePath = javacTrees.getPath(element);
        Tree leaf = treePath.getLeaf();
        if (treePath.getCompilationUnit() instanceof JCTree.JCCompilationUnit && leaf instanceof JCTree) {
            JCTree.JCCompilationUnit jccu = (JCTree.JCCompilationUnit) treePath.getCompilationUnit();
            for (JCTree jcTree : jccu.getImports()) {
                if (jcTree != null && jcTree instanceof JCTree.JCImport) {
                    JCTree.JCImport jcImport = (JCTree.JCImport) jcTree;
                    if (jcImport.qualid != null && jcImport.qualid instanceof JCTree.JCFieldAccess) {
                        JCTree.JCFieldAccess jcFieldAccess = (JCTree.JCFieldAccess) jcImport.qualid;
                        try {
                            if (packageName.equals(jcFieldAccess.selected.toString()) && className.equals(jcFieldAccess.name.toString())) {
                                return;
                            }
                        } catch (NullPointerException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
            java.util.List<JCTree> trees = new ArrayList<>();
            trees.addAll(jccu.defs);
            JCTree.JCImport jcImport = treeMaker.Import(treeMaker.Select(treeMaker.Ident(names.fromString(packageName)), names.fromString(className)), false);
            if (!trees.contains(jcImport)) {
                trees.add(trees.size() - 1, jcImport);
            }
            processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE, ">>> addImportInfo finished.");
            jccu.defs = List.from(trees);
        }
    }

    protected JCTree.JCExpression memberAccess(String components) {
        String[] componentArray = components.split("\\.");
        JCTree.JCExpression expr = treeMaker.Ident(names.fromString(componentArray[0]));
        for (int i = 1; i < componentArray.length; i++) {
            expr = treeMaker.Select(expr, names.fromString(componentArray[i]));
        }
        return expr;
    }


    /**
     * 创建范型类型，如<String,Object>
     *
     * @param typeNames 泛型的类型名称
     * @return
     */
    protected List<JCTree.JCExpression> createTypeargs(String... typeNames) {
        ListBuffer<JCTree.JCExpression> typeArgs = new ListBuffer<>();
        for (String typeName : typeNames) {
            typeArgs.append(treeMaker.Ident(names.fromString(typeName)));
        }
        return typeArgs.toList();
    }

    /**
     * 创建(变量、方法)类型 如Map<String,Object>
     *
     * @param typeName     类型名称
     * @param genericTypes 泛型类型列表
     * @return
     */
    protected JCTree.JCTypeApply createTypeApply(String typeName, List<JCTree.JCExpression> genericTypes) {
        String[] typeNames = typeName.split("\\.");

        JCTree.JCExpression type = null;
        for (String name : typeNames) {
            if (type == null) type = treeMaker.Ident(names.fromString(name));
            else type = treeMaker.Select(type,
                    names.fromString(name)
            );
        }

        JCTree.JCTypeApply typeApply = treeMaker.TypeApply(
                type,
                genericTypes
        );
        return typeApply;
    }

    /**
     * 直接通过类型创建(变量、方法)类型 如Map<String,Object>
     *
     * @param type         类型名称
     * @param genericTypes 泛型类型列表
     * @return
     */
    protected JCTree.JCTypeApply createTypeApply(JCTree.JCExpression type, List<JCTree.JCExpression> genericTypes) {
        JCTree.JCTypeApply typeApply = treeMaker.TypeApply(
                type,
                genericTypes
        );
        return typeApply;
    }

    /**
     * 创建对象 如 new HashMap<String,Object>
     *
     * @param classType 对象类型
     * @param params    new对象参数
     * @return
     */
    protected JCTree.JCNewClass createNewClass(JCTree.JCTypeApply classType, List<JCTree.JCExpression> params) {
        if (params == null) {
            params = List.nil();
        }
        JCTree.JCNewClass newClass = treeMaker.NewClass(
                null,
                List.nil(),
                classType, //对象类型
                params,    //new时的参数
                null);
        return newClass;
    }

    /**
     * 创建变量初始化赋值的语句，如 Map<String,Object> map = new HashMap<>()
     *
     * @param varName    变量名
     * @param varType    变量类型
     * @param objectType 对象类型
     * @return
     */
    protected JCTree.JCVariableDecl createVarAssigInit(String varName, JCTree.JCTypeApply varType, JCTree.JCNewClass objectType) {
        JCTree.JCVariableDecl varExpr = treeMaker.VarDef(
                treeMaker.Modifiers(Flags.BLOCK),
                names.fromString(varName),
                varType, objectType
        );
        return varExpr;
    }

    /**
     * 创建方法的参数
     *
     * @param varName
     * @param varType
     * @return
     */
    protected JCTree.JCVariableDecl createMethodParam(String varName, JCTree.JCExpression varType) {
        JCTree.JCVariableDecl varExpr = treeMaker.VarDef(
                treeMaker.Modifiers(Flags.PARAMETER),
                names.fromString(varName),
                varType, null
        );
        return varExpr;
    }

    /**
     * 创建调用表达式，如map.put("xxx","xxx")
     *
     * @param varName
     * @param funcName
     * @param params
     * @return
     */
    protected JCTree.JCMethodInvocation createMethodInvocation(String varName, String funcName, List<JCTree.JCExpression> params) {
        JCTree.JCMethodInvocation methodInvocation = treeMaker.Apply(
                List.nil(),                                             //没有类型参数
                treeMaker.Select(                                       //选择器map.put
                        treeMaker.Ident(names.fromString(varName)),
                        names.fromString(funcName)
                ),
                params
        );
        return methodInvocation;
    }


}